package priv.mill.factory;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.yaml.snakeyaml.Yaml;

public enum YamlFactory {

	INSTANCE;
	private YamlFactory() {
		yaml=new Yaml();
	}

	private Yaml yaml;

	public <T> List<T> getObjectList(Path path,String key) throws FileNotFoundException {
		try (FileInputStream io = new FileInputStream(path.toFile());){
			List<T> r = getObjectList(key, io);
			return r;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
		
	}

	public <T extends Object> List<T> getObjectList(String key, InputStream io) {
		Map<String,Object> load = yaml.load(io);
		Object object = load.get(key);
		if(!List.class.isInstance(object))return null;
		List<String> asList = (List<String>) object;
		return getObjectList(asList);
	}

	private <T> List<T> getObjectList(List<String> asList) {
		List<T> r=new ArrayList<>();
		asList.forEach(str->{
			try {
				Class<?> forName = Class.forName(str);
				if(forName==null)return;
				Constructor<?> constructor = forName.getConstructor();
				T newInstance = (T) constructor.newInstance();
				r.add(newInstance);
			} catch (Exception e) {
				e.printStackTrace();
			}
		});
		return r;
	}
	
	public <T extends Object> List<T> getObjectList4ClassPath(String key, String file) {
		InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(file);
		return getObjectList(key,resourceAsStream);
	}
	
	public <T> Map<String,T> getObjectMap(InputStream stream,String key) throws Exception{
		Map<String,Object> load = yaml.load(stream);
		Map<String,T> r=new HashMap<>();
		Object object = load.get(key);
		getObjectMap(key, r, object);
		return r;
		
	}

	private <T> void getObjectMap(String key, Map<String, T> r, Object object)
			throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		if(List.class.isInstance(object)) {
			r.put(key, (T) getObjectList((List<String>) object));
		}else if(Map.class.isInstance(object)) {
			
			for (Entry<String, Object> item : ((Map<String,Object>)object).entrySet()) {
				getObjectMap(item.getKey(),r,item.getValue());
			}
		}else if(String.class.isInstance(object)) {
			Class<?> forName = Class.forName(object.toString());
			if(forName==null)return;
			r.put(key, (T) forName.newInstance());
		}
	}

	public<T> Map<String, T> getObjectMap(String file, String key) {
		InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(file);
		try {
			return getObjectMap(resourceAsStream, key);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
}
